package com.autumn.config.services.impl;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.autumn.common.api.application.dto.input.DefaultPrimaryKeyInput;
import com.autumn.config.api.consts.ConfigureConsts.StatusConsts;
import com.autumn.config.api.dto.input.StatusInput;
import com.autumn.config.api.services.IConfigureService;
import com.autumn.config.entities.IAppConfigureDefaultEntity;
import com.autumn.config.entities.IStatusEntity;
import com.autumn.config.util.ServiceUtils;
import com.autumn.domain.repositories.IDefaultEntityRepository;
import com.autumn.mybatis.criterion.LockModeEnum;
import com.autumn.mybatis.criterion.SpecifyUpdate;
import com.autumn.util.AutoMapUtils;
import com.autumn.util.DataRollbackException;
import com.autumn.util.ExceptionUtils;
import com.autumn.util.data.DbAuditingUtils;
import com.autumn.util.data.DbQueryUtils;
import com.autumn.util.reflect.ReflectUtils;

/**
 * 抽象服务
 *
 * @author 老码农
 * <p>
 * Description
 * </p>
 * @date 2018-01-01 02:02:59
 */
public abstract class AbstractConfigureService<TEntity extends IStatusEntity, TQueryEntity extends IStatusEntity, TAddInput, TModifyInput, TOutput>
        extends AbstractService implements IConfigureService<TAddInput, TModifyInput, TOutput> {

    /**
     * 编辑仓储
     */
    @Autowired
    protected IDefaultEntityRepository<TEntity> repository;

    /**
     * 查询仓储
     */
    @Autowired
    protected IDefaultEntityRepository<TQueryEntity> queryRepository;

    private final Class<TEntity> entityClass;
    private final Class<TQueryEntity> queryEntityClass;
    private final Class<TAddInput> addInputClass;
    private final Class<TModifyInput> modifyInputClass;
    private final Class<TOutput> outputClass;
    private final Map<String, Class<?>> genericActualArgumentsTypeMap;

    @SuppressWarnings("unchecked")
    public AbstractConfigureService() {
        Map<String, Class<?>> map = ReflectUtils.getGenericActualArgumentsTypeMap(this.getClass());
        this.entityClass = (Class<TEntity>) map.get("TEntity");
        this.queryEntityClass = (Class<TQueryEntity>) map.get("TQueryEntity");
        this.addInputClass = (Class<TAddInput>) map.get("TAddInput");
        this.modifyInputClass = (Class<TModifyInput>) map.get("TModifyInput");
        this.outputClass = (Class<TOutput>) map.get("TOutput");
        this.genericActualArgumentsTypeMap = map;
    }

    /**
     * 获取实体类型
     *
     * @return
     */
    public final Class<TEntity> getEntityClass() {
        return entityClass;
    }

    /**
     * 获取查询实体类型
     *
     * @return
     */
    public final Class<TQueryEntity> getQueryEntityClass() {
        return queryEntityClass;
    }

    /**
     * 获取添加输入类型
     *
     * @return
     */
    public final Class<TAddInput> getAddInputClass() {
        return addInputClass;
    }

    /**
     * 获取修改输入类型
     *
     * @return
     */
    public final Class<TModifyInput> getModifyInputClass() {
        return modifyInputClass;
    }

    /**
     * 获取输出类型
     *
     * @return
     */
    public final Class<TOutput> getOutputClass() {
        return outputClass;
    }

    /**
     * 是否存在
     *
     * @param propertyMap 属性Map
     * @return
     */
    protected boolean exist(Map<String, Object> propertyMap) {
        return ServiceUtils.exist(this.repository, this.getEntityClass(), propertyMap);
    }

    /**
     * 是否存在
     *
     * @param propertyName 属性名称
     * @param value        属性值
     * @return
     */
    protected boolean exist(String propertyName, Object value) {
        return ServiceUtils.exist(this.repository, this.getEntityClass(), propertyName, value);
    }

    /**
     * 基于id删除
     *
     * @param id
     * @return
     */
    protected TEntity deleteById(Long id) {
        TEntity result = this.getById(id);
        if (result == null) {
            ExceptionUtils.throwValidationException("无法删除不存在的数据。");
        }
        if (result.getStatus().equals(StatusConsts.STATUS_RELEASE)) {
            ExceptionUtils.throwValidationException("不能删除已发布的数据。");
        }
        if (DbAuditingUtils.deleteById(this.repository, this.getEntityClass(), id) <= 0) {
            ExceptionUtils.throwValidationException("无法删除不存在的数据。");
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public void delete(DefaultPrimaryKeyInput input) {
        if (input == null || input.getId() == null) {
            ExceptionUtils.throwValidationException("Id 不能为null。");
        }
        this.deleteById(input.getId());
    }

    @Override
    @Transactional(rollbackFor = DataRollbackException.class)
    public TOutput updateStatus(StatusInput input) {
        if (this.getEntityClass().equals(this.getQueryEntityClass())) {
            return ServiceUtils.updateStatus(this.repository, this.getEntityClass(), this.getOutputClass(), input);
        }
        ServiceUtils.updateStatus(this.repository, this.getEntityClass(), input);
        return AutoMapUtils.map(this.getQueryById(input.getId()), this.getOutputClass());
    }

    /**
     * 更新默认
     *
     * @param appDefaultEntity 应用默认实体
     */
    protected void updateDefault(IAppConfigureDefaultEntity appDefaultEntity) {
        if (appDefaultEntity.getIsDefault()) {
            SpecifyUpdate spe = new SpecifyUpdate(appDefaultEntity.getClass());
            spe.eq("appId", appDefaultEntity.getAppId()).set("isDefault", false);
            this.repository.updateBySpecify(spe.builderSection());
        }
    }

    /**
     * 获取
     *
     * @param id
     * @return
     */
    protected final TEntity getById(Long id) {
        return DbQueryUtils.queryById(this.repository, this.getEntityClass(), id);
    }

    /**
     * 获取
     *
     * @param id       值
     * @param lockMode 锁
     * @return
     */
    protected final TEntity getById(Long id, LockModeEnum lockMode) {
        return DbQueryUtils.queryById(this.repository, this.getEntityClass(), id);
    }

    /**
     * 获取查询
     *
     * @param id
     * @return
     */
    protected final TQueryEntity getQueryById(Long id) {
        return DbQueryUtils.queryById(this.queryRepository, this.getQueryEntityClass(), id);
    }

    /**
     * 获取查询
     *
     * @param id       值
     * @param lockMode 锁
     * @return
     */
    protected final TQueryEntity getQueryById(Long id, LockModeEnum lockMode) {
        return DbQueryUtils.queryById(this.queryRepository, this.getQueryEntityClass(), id, lockMode);
    }

    @Override
    public TOutput queryById(DefaultPrimaryKeyInput input) {
        if (input == null || input.getId() == null) {
            ExceptionUtils.throwValidationException("Id 不能为null。");
        }
        TQueryEntity result = this.getQueryById(input.getId());
        return AutoMapUtils.map(result, this.getOutputClass());
    }

    /**
     * 获取泛型实际参数类型Map
     *
     * @return
     */
    public Map<String, Class<?>> getGenericActualArgumentsTypeMap() {
        return genericActualArgumentsTypeMap;
    }
}
